#ifndef	_XICACHE_H_
#define	_XICACHE_H_

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * xicache.h
 *
 * The Xicache holds pre-decoded instructions for the
 * core of the simulator, for future eXecution, it
 * is also used as the core support for breakpoints
 * and other code insertion events. Ultimately
 * other tracing tools etc. may also be inserted as
 * functions to be interposed via the e-cache
 * between the decoded instruction form and the
 * main execution routine.
 *
 * In this way a call path for a certain instruction
 * might look like;
 *
 * stat_gather() ->
 *		breakpoint_check()->
 *				instruction();
 *
 * Thus augmentation can be done on a per-instruction
 * basis, but without having to pay the test cost
 * in the main execution loop.
 *
 */

#if 0 /* } in simcore.h instead */
typedef struct XICACHE_INSTN xicache_instn_t;
typedef struct XICACHE_LINE xicache_line_t;
typedef struct XICACHE xicache_t;
typedef	union DECODED_INSTN decoded_instn_t;
#endif	/* } */

#include "basics.h"


#if PERFORMANCE_CHECK /* { */
#define	XIC_MISS(sp)	do { (sp)->xic_misses++; } while (0)
#else
#define	XIC_MISS(sp)	do { } while (0)
#endif	/* } */

union DECODED_INSTN {
	struct {
		uint16_t	rs1o;
		sint16_t	simm16;
		uint16_t	rdo;
	} rri;		/* register + immediate -> register */

	struct {
		uint16_t	rs1o;
		uint16_t	rs2o;
		uint16_t	rdo;
	} rrr;		/* register + register -> register */

	struct {
		sint32_t	simm32;
		uint16_t	rdo;
	} rsimm32;

	struct {
		uint32_t	uimm32;
		uint16_t	rdo;
	} ruimm32;

	struct {
		uint16_t	rs1o;
		sint32_t	offset32;
	} breg;		/* branch on register value */

	struct	{
		sint32_t	offset32;
		uint8_t		fcc;	/* fcc number for FBPfcc */
	} brcond;

	struct {
		uint16_t	rs1o;
		sint16_t	simm16;
		uint8_t		rd_num;
		uint8_t		asi_num;
		uint8_t		op;
	} sp_asi_imm;	/* format for sparc asi ld/st/cas imm form instns */

	struct {
		uint16_t	rs1o;
		uint16_t	rs2o;
		uint8_t		rd_num;
		uint8_t		asi_num;
		uint8_t		op;
	} sp_asi_rrr;	/* format for sparc asi ld/st/cas rrr form instns */


	struct {
		uint16_t	rs1o;
		uint16_t	rs2o;
		uint8_t		cond;	/* 4 bits */
		uint8_t		cc;	/* =0 for icc, 1 for xcc */
	} sp_trap_rrr;	/* format for sparc trap instn */

	struct {
		uint16_t	rs1o;
		sint16_t	simm16;
		uint8_t		cond;	/* 4 bits */
		uint8_t		cc;	/* =0 for icc, 1 for xcc */
	} sp_trap_imm;	/* format for sparc trap instn */

	struct {
		uint8_t		cond;	/* 4 bits */
		uint8_t		cc;	/* =0 for icc, 1 for xcc */
		uint16_t	rs2o;
		uint16_t	rdo;
	} sp_movcc_rr;	/* format for sparc movcc instn */

	struct {
		uint8_t		cond;	/* 4 bits */
		uint8_t		cc;	/* =0 for icc, 1 for xcc */
		sint16_t	simm16;
		uint16_t	rdo;
	} sp_movcc_imm;	/* format for sparc movcc instn */

	sint32_t	call_off32;	/* offset for call instn - NOTE: must be signed !*/

	uint32_t	ill_reason;	/* coded reason for why instruction is illegal*/

	uint32_t	misc_bits;	/* for all those other instns which need additional stuff */
};


	/*
	 * String decoding for why instruction is illegal (xcip->ill_reason)
	 *
	 */

extern char * illegal_reason_str[];


struct XICACHE_INSTN {
	void 	        (*exec_funcp)(simcpu_t * sp, xicache_instn_t *);
	uint32_t	rawi;
	decoded_instn_t	di;
};




	/**/
	/* The non-dynamic E-cache versions - far far more efficient*/
	/**/
#define	XICACHE_SIZE_BITS		20	/* 1MB of decoded instructions */

#define	XICACHE_LINE_SIZE_BITS		13	/* allow each chunk to be 8K */
#define	XICACHE_LINE_SIZE		(1ULL<<XICACHE_LINE_SIZE_BITS)
#define	XICACHE_LINE_OFFSET_MASK	(XICACHE_LINE_SIZE-1)
#define	XICACHE_LINES_BITS		(XICACHE_SIZE_BITS-XICACHE_LINE_SIZE_BITS)
#define	XICACHE_NUM_LINES		(1ULL<<XICACHE_LINES_BITS)
#define	XICACHE_LINE_MASK		(XICACHE_NUM_LINES-1)
#define	XICACHE_LINE_INSTRS		(XICACHE_LINE_SIZE >> 2)

	/* define the instruction cache to match the same number of lines */
#define	XICACHE_INSTR_SHIFT_BITS	2
#define	XICACHE_INSTR_ALIGN_MASK	((1ULL<<XICACHE_INSTR_SHIFT_BITS)-1ULL)
#define	XICACHE_NUM_INSTRS		(1ULL<<(XICACHE_LINE_SIZE_BITS-XICACHE_INSTR_SHIFT_BITS+XICACHE_LINES_BITS))
#define	XICACHE_NUM_INSTR_MASK		(XICACHE_NUM_INSTRS-1)

#define	XICACHE_TAG_PURE_MASK		(~XICACHE_LINE_OFFSET_MASK)

	/* presumes RISC architectures with fixed alignment requirements */
#define	XICACHE_TAG_MASK		(XICACHE_TAG_PURE_MASK|XICACHE_INSTR_ALIGN_MASK)


struct XICACHE_LINE {
	tvaddr_t	tag;
#define	XC_INVALID_TAG	(~(uint64_t)0)
	uint64_t	memoryoffset;
#if XIC_STATS	/* XIC_STATS { */
	uint32_t	miss;
	uint32_t	hit;
#endif	/* } XIC_STATS */
};



struct XICACHE {
	xicache_instn_t	instn[ XICACHE_NUM_INSTRS ];
	xicache_line_t	line[ XICACHE_NUM_LINES ];

#if XIC_STATS	/* XIC_STATS { */
	uint32_t	flush_count;
	uint32_t	init_count;
	uint32_t	decode_miss;
#endif	/* } XIC_STATS */
};


/* Pick a real illegal instruction!! */
#define	XICACHE_DEAD_INSTN	0x02000000


#define	  XICACHE_LINE_IDX(p, _pad)	(((_pad)>>XICACHE_LINE_SIZE_BITS(p)) & XICACHE_LINE_MASK(p))
#define	  XICACHE_LINE_ADDR_TAG(p,_pad)	((_pad) & ~(XICACHE_LINE_OFFSET_MASK(p)))


	/*
	 * X cache support functions
	 */

extern xicache_t * xicache_alloc();
extern void xicache_dump_stats(simcpu_t * cpup, FILE * outp);
extern void xicache_flush_line(simcpu_t * cpup, tvaddr_t va);
extern void xicache_instn_flush(simcpu_t * sp);
extern void xicache_trans_flush(simcpu_t * sp);
extern void xicache_full_flush(simcpu_t * sp);
extern void xicache_clobber_line_decodes(simcpu_t * sp, tvaddr_t tagva);




	/*
	 * Macros for setting and using the decoded
	 * instruction form types
	 */



#define	RegPtr(_sp,_off)	(((uint8_t*)&(_sp->intreg[0])) + (_off))
#define	UReg(_sp,_off)		(*(uint64_t*)RegPtr(_sp, _off))
#define	SReg(_sp,_off)		(*(sint64_t*)RegPtr(_sp, _off))
#define FP32Reg(_sp,_off)	(*(uint32_t*)RegPtr(_sp, _off))

	/* Simple version for when real register numbers are required */
#define	IReg(_n)		(sp->intreg[_n])


	/* Macros for the decoded instruction implementations */
	/* assumes simcpu_t * sp, and xicache_instn_t * xcip */

#define	Rpc	(sp->pc)
#define	Rnpc	(sp->npc)

#define	Rdest	UReg( sp, xcip->di.rri.rdo )
#define	Rsrc1	UReg( sp, xcip->di.rri.rs1o )
#define	Rsrc2	UReg( sp, xcip->di.rrr.rs2o )
#define	SRdest	SReg( sp, xcip->di.rri.rdo )
#define	SRsrc1	SReg( sp, xcip->di.rri.rs1o )
#define	SRsrc2	SReg( sp, xcip->di.rrr.rs2o )
#define	F32src1	FP32Reg( sp, xcip->di.rri.rs1o )
#define	F32src2	FP32Reg( sp, xcip->di.rrr.rs2o )
#define	F64src1	Rsrc1
#define	F64src2	Rsrc2
#define	F32dest	FP32Reg( sp, xcip->di.rri.rdo )
#define	F64dest	Rdest

#define	Simm16	((sint64_t)(xcip->di.rri.simm16))
#define	Simm32	((sint64_t)(xcip->di.rsimm32.simm32))
#define	Uimm32	((uint64_t)(xcip->di.ruimm32.uimm32))

#define	SBRoffset32	((sint64_t)(xcip->di.brcond.offset32))
#define	SBRfcc		((sint64_t)(xcip->di.brcond.fcc))

		/* Offset for branch on reg value */
#define	SBRreg_off32	((sint64_t)(xcip->di.breg.offset32))

	/* Annoyingly undo the pointer encodings for raw reg nums */

#define	Zero_Reg(_offset)	((_offset)==0)

#define	Rdest_num	(xcip->di.rri.rdo / sizeof(sp->intreg[0]))
#define	Rsrc1_num	(xcip->di.rri.rs1o / sizeof(sp->intreg[0]))
#define	Rsrc2_num	(xcip->di.rri.rs2o / sizeof(sp->intreg[0]))

#define	Misc32		(xcip->di.misc_bits)


	/*
	 * Macros for the decoder to write to the xicache
	 * decoded forms of instructions.
	 */

#define	IReg_Offset(_rn)	((unsigned)(uint64_t)&(((simcpu_t *)0)->intreg[(_rn)]))

#define	SET_OP_RD(_n)		do { xcip->di.rri.rdo = IReg_Offset( _n ); } while (0)
#define	SET_OP_RS1(_n)		do { xcip->di.rri.rs1o = IReg_Offset( _n ); } while (0)
#define	SET_OP_RS2(_n)		do { xcip->di.rrr.rs2o = IReg_Offset( _n ); } while (0)

	/* Index value is for smallest FP register size */
#define	FPReg_Offset(_rn)	((unsigned)(uint64_t)&(((simcpu_t *)0)->fpreg.s32[(_rn)]))

#define	SET_OP_FPRD(_n)		do { xcip->di.rri.rdo = FPReg_Offset( _n ); } while (0)
#define	SET_OP_FPRS1(_n)	do { xcip->di.rri.rs1o = FPReg_Offset( _n ); } while (0)
#define	SET_OP_FPRS2(_n)	do { xcip->di.rrr.rs2o = FPReg_Offset( _n ); } while (0)

#define	SET_OP_SIMM16(_n)	do { xcip->di.rri.simm16 = _n; } while (0)
#define	SET_OP_SIMM32(_n)	do { xcip->di.rsimm32.simm32 = _n; } while (0)
#define	SET_OP_UIMM32(_n)	do { xcip->di.ruimm32.uimm32 = _n; } while (0)

#define	SET_OP_BREGOFF32(_n)	do { xcip->di.breg.offset32 = (_n); } while (0)
#define	SET_OP_BROFF32(_n)	do { xcip->di.brcond.offset32 = (_n); } while (0)
#define	SET_OP_BR_FCC(_n)	do { xcip->di.brcond.fcc = (_n); } while (0)

#define	SET_OP_ASI_OP(_n)	do { xcip->di.sp_asi_imm.op = (_n) ; } while (0)
#define	SET_OP_ASI_RD(_n)	do { xcip->di.sp_asi_imm.rd_num = (_n) ; } while (0)
#define	SET_OP_ASI_FPRD(_n)	do { xcip->di.sp_asi_imm.rd_num = (_n) ; } while (0)
#define	SET_OP_ASI_NUM(_n)	do { xcip->di.sp_asi_imm.asi_num = (_n) ; } while (0)

#define	ASI_Rdest	(xcip->di.sp_asi_imm.rd_num)
#define	ASI_num		(xcip->di.sp_asi_imm.asi_num)
#define	ASI_op		(xcip->di.sp_asi_imm.op)

#define	SET_OP_TRAP_CC(_cc)	do { xcip->di.sp_trap_rrr.cc = (_cc); } while (0)
#define	SET_OP_TRAP_COND(_c)	do { xcip->di.sp_trap_rrr.cond = (_c); } while (0)

#define	TRAP_cc			(xcip->di.sp_trap_rrr.cc)
#define	TRAP_cond		(xcip->di.sp_trap_rrr.cond)

#define	SET_OP_MOVCC_CC(_cc)	do { xcip->di.sp_movcc_rr.cc = (_cc); } while (0)
#define	SET_OP_MOVCC_COND(_c)	do { xcip->di.sp_movcc_rr.cond = (_c); } while (0)

#define	MOVCC_cc		(xcip->di.sp_movcc_rr.cc)
#define	MOVCC_cond		(xcip->di.sp_movcc_rr.cond)

	/*
	 * When an illegal instruction is encountered we set an internal
	 * code to give ourselves a clue as to why the decoder thought it
	 * was illegal
	 */

#define	SET_OP_ILL_REASON(_r)	do { xcip->di.ill_reason = (uint32_t)(_r); } while (0)

	/*
	 * Instructions for which we have no other obvious encoding
	 * get to have a custom 32 bit field for their own bit encodings
	 */

#define	SET_OP_MISC_BITS(_b)	do { xcip->di.misc_bits = (uint32_t)(_b); } while (0)

#ifdef	__cplusplus
}
#endif

#endif	/* _XICACHE_H_ */
